package com.gofun.framework.redis;

import java.io.Serializable;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.gofun.framework.redis.RedisDBIndex.RedisModel;


/**
 * 
 * @Project : framework-redis
 * @Program Name : com.ljt.framework.redis.RedisUtil.java
 * @Description : TODO redis工具类
 * @Author : bingo刑天
 * @Creation Date : 2016年7月5日 下午11:04:26
 * @ModificationHistory Who When What ---------- ------------- -----------------------------------
 *                      bingo刑天 2016年7月5日 create
 */
@SuppressWarnings("unchecked")
@Component
public class RedisUtil {
  private static final Logger logger = LoggerFactory.getLogger(RedisUtil.class);
  @SuppressWarnings("rawtypes")
  @Autowired
  private RedisTemplate redisTemplate;

  // 新增redis
  /**
   * 
   * @Description : TODO 向指定库中增加redis
   * @param tableName 数据对应的表名
   * @param fieldName 数据对应的字段名（非必需）
   * @param key 数据对应的唯一标示
   * @param value 数据
   * @param timeout 过期时间
   * @param unit 过期时间单位
   * @param modelName 模块名称
   * @return : void 无返回值
   * @Creation Date : 2016年7月13日16:37:30
   * @Author : bingo刑天
   */
  public boolean setRedis(String tableName, String fieldName, String key, Object value,
      long timeout, TimeUnit unit, String modelName) {
    boolean result = false;
    String ljtKey = buildKey(tableName, fieldName, key);
    int redisDBIndex = getredisDBIndex(modelName);
    ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
    ((JedisConnectionFactory) redisTemplate.getConnectionFactory()).setDatabase(redisDBIndex);
    logger.debug("Set Redis With key=[{}],value=[{}] in RedisDB[{}].Start!", ljtKey, value,
        redisDBIndex);
    operations.set(ljtKey, value, timeout, unit);
    result = true;
    logger.debug("Set Redis With key=[{}],value=[{}] in RedisDB[{}].End!", ljtKey, value,
        redisDBIndex);
    return result;
  }

  /**
   * 
   * @Description : TODO 向指定库中增加redis（无指定时间）
   * @param tableName 数据对应的表名
   * @param fieldName 数据对应的字段名（非必需）
   * @param key 数据对应的唯一标示
   * @param value 数据
   * @param modelName 模块名称
   * @return : void 无返回值
   * @Creation Date : 2016年7月13日16:37:30
   * @Author : bingo刑天
   */
  public boolean setRedis(String tableName, String fieldName, String key, Object value,
      String modelName) {
    return setRedis(tableName, fieldName, key, value, 1, TimeUnit.DAYS, modelName);
  }

  // 删除redis
  /**
   * 
   * @Description : TODO 从指定库中批量删除
   * @param tableName 数据对应的表名
   * @param fieldName 数据对应的字段名（非必需）
   * @param keys 数据对应的唯一标示 set集合
   * @param modelName 模块名称
   * @return : void 无返回值
   * @Creation Date : 2016年7月6日 上午9:55:41
   * @Author : bingo刑天
   */
  public void remove(String tableName, String fieldName, String modelName, Set<String> keys) {
    for (String key : keys) {
      removeRedis(tableName, fieldName, key, modelName);
    }
  }

  /**
   * 
   * @Description : TODO 从指定库中删除key
   * @param tableName 数据对应的表名
   * @param fieldName 数据对应的字段名（非必需）
   * @param key 数据对应的唯一标示
   * @param modelName 模块名称
   * @return : void 无返回值
   * @Creation Date : 2016年7月13日16:36:15
   * @Author : bingo刑天
   */
  public void removePattern(String tableName, String fieldName, String key, String modelName) {
    int redisDBIndex = getredisDBIndex(modelName);
    String ljtKey = buildKey(tableName, fieldName, key);
    ((JedisConnectionFactory) redisTemplate.getConnectionFactory()).setDatabase(redisDBIndex);
    Set<Serializable> keys = redisTemplate.keys(ljtKey);
    logger.debug("Delete Redis With key=[{}]form RedisDB[{}].Start!", ljtKey, redisDBIndex);
    if (keys.size() > 0) {
      redisTemplate.delete(keys);
    }
    logger.debug("Delete Redis With key=[{}]form RedisDB[{}].End!", ljtKey, redisDBIndex);
  }

  /**
   * 
   * @Description : TODO 从指定库中删除key
   * @param tableName 数据对应的表名
   * @param fieldName 数据对应的字段名（非必需）
   * @param key 数据对应的唯一标示
   * @param modelName 模块名称
   * @return : void 无返回值
   * @Creation Date : 2016年7月13日16:36:15
   * @Author : bingo刑天
   */
  public void removeRedis(String tableName, String fieldName, String key, String modelName) {
    int redisDBIndex = getredisDBIndex(modelName);
    String ljtKey = buildKey(tableName, fieldName, key);
    if (exists(tableName, fieldName, key, modelName)) {
      ((JedisConnectionFactory) redisTemplate.getConnectionFactory()).setDatabase(redisDBIndex);
      logger
          .debug("Delete Redis With key=[" + ljtKey + "]form RedisDB[" + redisDBIndex + "].Start!");
      redisTemplate.delete(ljtKey);
      logger.debug("Delete Redis With key=[" + ljtKey + "]form RedisDB[" + redisDBIndex + "].End!");
    }
  }

  // 检查状态
  /**
   * 
   * @Description : TODO 检查key是否存在
   * @param tableName 数据对应的表名
   * @param fieldName 数据对应的字段名（非必需）
   * @param key 数据对应的唯一标示
   * @param modelName 模块名称
   * @return exists 存在状态
   * @Creation Date : 2016年7月13日16:36:58
   * @Author : bingo刑天
   */
  public boolean exists(String tableName, String fieldName, String key, String modelName) {
    String ljtKey = buildKey(tableName, fieldName, key);
    int redisDBIndex = getredisDBIndex(modelName);
    boolean exists = false;
    ((JedisConnectionFactory) redisTemplate.getConnectionFactory()).setDatabase(redisDBIndex);
    logger.debug("Check Redis With key=[{}]form RedisDB[{}].Start!", ljtKey, redisDBIndex);
    exists = redisTemplate.hasKey(ljtKey);
    logger.debug("Check Redis With key=[{}]form RedisDB[{}].End!", ljtKey, redisDBIndex);
    return exists;
  }

  // 获取redis
  /**
   * 
   * @Description : TODO 从指定库获取redis
   * @param tableName 数据对应的表名
   * @param fieldName 数据对应的字段名（非必需）
   * @param key 数据对应的唯一标示
   * @param modelName 模块名称
   * @return value 缓存的内容
   * @Creation Date : 2016年7月6日 上午9:51:22
   * @Author : bingo刑天
   */
  public Object getRedis(String tableName, String fieldName, String key, String modelName) {
    Object result = null;
    String ljtKey = buildKey(tableName, fieldName, key);
    int redisDBIndex = getredisDBIndex(modelName);
    ((JedisConnectionFactory) redisTemplate.getConnectionFactory()).setDatabase(redisDBIndex);
    ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
    logger.debug("Get Redis With key=[{}]form RedisDB[{}].Start!", ljtKey, redisDBIndex);
    result = operations.get(ljtKey);
    logger.debug("Get Redis With key=[{}]form RedisDB[{}].End!", ljtKey, redisDBIndex);
    return result;
  }


  // 清库

  /**
   * 
   * @Description : TODO 清空指定库所有redis
   * @param modelName 模块名称
   * @return : void 无返回值
   * @Creation Date : 2016年7月6日 上午9:52:58
   * @Author : bingo刑天
   */
  public void flushRedisDB(String modelName) {
    int redisDBIndex = getredisDBIndex(modelName);
    ((JedisConnectionFactory) redisTemplate.getConnectionFactory()).setDatabase(redisDBIndex);
    logger.debug("Flush Redis db With RedisDB[{}].Start!", redisDBIndex);
    redisTemplate.getConnectionFactory().getConnection().flushDb();
    logger.debug("Flush Redis db With RedisDB[{}].End!", redisDBIndex);
  }

  // 清除所有
  /**
   * 
   * @Description : TODO 清空redis所有库
   * @return : void 无返回值
   * @Creation Date : 2016年7月6日 上午9:53:35
   * @Author : bingo刑天
   */
  public void flushAll() {
    logger.debug("Flush Redis Alldb Start!");
    redisTemplate.getConnectionFactory().getConnection().flushAll();
    logger.debug("Flush Redis Alldb End!");
  }

  // 内部工具
  /**
   * 
   * @Description : TODO 组装redis中key
   * @param tableName 数据对应的表名
   * @param fieldName 数据对应的字段名（非必需）
   * @param key 数据对应的唯一标示
   * @return : String 组装key
   * @Creation Date : 2016年7月6日 上午9:53:58
   * @Author : bingo刑天
   */
  private static String buildKey(String tableName, String fieldName, String key) {
    if (!StringUtils.hasText(tableName)) {
      throw new NullPointerException("tableName is empty!");
    }
    logger.debug("BuildKey with tableName=[{}],fieldName=[{}],key=[{}].Start!", tableName,
        fieldName, key);
    StringBuffer ljtKey = new StringBuffer();
    ljtKey.append(tableName);
    if (StringUtils.hasText(fieldName)) {
      ljtKey.append(".");
      ljtKey.append(fieldName);
    }
    ljtKey.append(":");
    ljtKey.append(key);
    logger.debug("BuildKey with tableName=[{}],fieldName=[{}],key=[{}.End!", tableName, fieldName,
        key);
    return ljtKey.toString();
  }

  /**
   * 
   * @Description : TODO 根据模块名称获取数据库索引
   * @param modelName 模块名称
   * @return : int 模块对应db索引
   * @Creation Date : 2016年7月6日 上午9:54:46
   * @Author : bingo刑天
   */
  private static int getredisDBIndex(String modelName) {
    logger.debug("GetredisDBIndex with modelName=[{}].Start!", modelName);
    if (!StringUtils.hasText(modelName)) {
      throw new NullPointerException("modelName is empty!");
    }
    int redisDBIndex = 0;
    for (RedisModel model : RedisModel.values()) {
      if (model.modelName.equalsIgnoreCase(modelName))
        redisDBIndex = model.code;
    }
    logger.debug("GetredisDBIndex with modelName=[{}].End!", modelName);
    return redisDBIndex;
  }

}


